## Множественное наследование


Одной из отличительных особенностей языка Python является поддержка множественного наследования, то есть один класс можно унаследовать от нескольких классов:

```python
#  класс работника
class Employee:
    def work(self):
        print("Employee works")
 
 
#  класс студента
class Student:
    def study(self):
        print("Student studies")
 
 
class WorkingStudent(Employee, Student):        # Наследование от классов Employee и Student
    pass
 
 
# класс работающего студента
tom = WorkingStudent()
tom.work()      # Employee works
tom.study()     # Student studies

```


Здесь определен класс `Employee`, который представляет сотрудника фирмы, и класс Student, который представляет учащегося студента. 

Класс `WorkingStudent`, который представляет работающего студента, не определяет никакого функционала, поэтому в нем определен оператор pass. 

Класс `WorkingStudent` просто наследует функционал от двух классов `Employee` и `Student`. 
Соответственно у объекта этого класса мы можем вызвать методы обоих классов.

При этом наследуемые классы могут более сложными по функциональности, например:

```python
class Employee:
 
    def __init__(self, name):
        self.__name = name
 
    @property
    def name(self):
        return self.__name
 
    def work(self):
        print(f"{self.name} works")
 
 
class Student:
 
    def __init__(self, name):
        self.__name = name
 
    @property
    def name(self):
        return self.__name
 
    def study(self):
        print(f"{self.name} studies")
 
 
class WorkingStudent(Employee, Student):
    pass
 
 
tom = WorkingStudent("Tom")
tom.work()      # Tom works
tom.study()     # Tom studies

```

Множественное наследование может показаться удобным, тем не менее оно может привести к путанице, если оба наследуемых класса содержат методы/атрибуты с одинаковыми именами. Например:

```python
class Employee:
    def do(self):
        print("Employee works")
  
class Student:
    def do(self):
        print("Student studies")
  
  
# class WorkingStudent(Student,Employee):
class WorkingStudent(Employee, Student):
    pass
 
tom = WorkingStudent()
tom.do()     # ?

```

Оба базовых класса - `Employee` и `Worker` определяют метод `do`, который выводит разную строку на консоль.

Какую именно из этих реализаций будет использовать класс-наследник `WorkingStudent`? 

При определении класса первым в списке базовых классов идет класс `Employee`

`class WorkingStudent(Employee, Student)`

Поэтому реализация метода do будут браться из класса `Employee`.

Если бы мы поменяли очередность классов:

`class WorkingStudent(Student,Employee)`

то использовалась бы реализация класса Student

При необходимости мы можем программным образом посмотреть очередность применения функционала базовых классов. Для этого применяется атрибут `__mro__`, либо метод `mro()`:

```python
print(WorkingStudent.__mro__)
print(WorkingStudent.mro())
```